"""
路由模块（包含模型定义）
"""
from fastapi import APIRouter
from fastapi.responses import StreamingResponse
from pydantic import BaseModel, Field
from typing import Literal, Generic, TypeVar, Optional
from .service import AudioRecorder
import asyncio
import json
from collections import deque
from datetime import datetime

# ==================== 模型定义 ====================

T = TypeVar('T')


class ApiResponse(BaseModel, Generic[T]):
    """统一响应格式"""
    code: int
    message: str
    data: Optional[T] = None


# 便捷响应函数
def success_response(data=None, message="操作成功"):
    return ApiResponse(code=200, message=message, data=data)


def bad_request_response(message):
    return ApiResponse(code=400, message=message, data=None)


def internal_error_response(message):
    return ApiResponse(code=500, message=message, data=None)


# ==================== 路由定义 ====================

router = APIRouter()
audio_recorder = AudioRecorder()

# 用于存储每个会话的消息队列
message_queues = {}


def text_callback(session_id: str):
    """创建文本回调函数"""
    def callback(data):
        if session_id in message_queues:
            message_queues[session_id].append(data)
    return callback


@router.get("/")
async def root():
    """根路径"""
    return success_response(
        data={"service": "ASR", "version": "1.0.0"},
        message="语音识别服务运行中"
    )


@router.post("/recording/start/{session_id}")
async def start_recording(session_id: str):
    """启动录音"""
    try:
        if audio_recorder.is_recording:
            return bad_request_response("录音已在进行中")
        
        message_queues[session_id] = deque(maxlen=1000)
        audio_recorder.start_recording(text_callback(session_id))
        
        return success_response(
            data={"session_id": session_id, "status": "recording_started"},
            message="录音已启动"
        )
    except Exception as e:
        return internal_error_response(f"启动失败: {str(e)}")


@router.post("/recording/stop")
async def stop_recording():
    """停止录音"""
    try:
        if not audio_recorder.is_recording:
            return bad_request_response("当前没有正在进行的录音")
        
        audio_recorder.stop_recording()
        
        return success_response(
            data={"status": "recording_stopped"},
            message="录音已停止"
        )
    except Exception as e:
        return internal_error_response(f"停止失败: {str(e)}")


@router.get("/stream/recognize/{session_id}")
async def stream_recognize(session_id: str):
    """SSE流式识别 
    
    事件格式：
    - start: 连接建立
      data: {"status": "connected", "timestamp": str, "session_id": str}
    - message: 识别结果
      data: {"type": "partial/final", "text": str, "timestamp": str, "session_id": str}
    - ping: 心跳
      data: {"status": "ping", "timestamp": str, "session_id": str}
    - end: 结束
      data: {"status": "completed", "timestamp": str, "session_id": str}
    - error: 错误
      data: {"code": int, "message": str, "timestamp": str, "session_id": str}
    """
    async def event_generator():
        async def sse_event(event: str, data: dict) -> str:
            """格式化 SSE 事件"""
            return f"event: {event}\ndata: {json.dumps(data, ensure_ascii=False)}\n\n"
        
        # start 事件
        yield await sse_event(
            "start",
            {
                "status": "connected",
                "timestamp": datetime.now().isoformat(),
                "session_id": session_id,
            }
        )
        
        queue: asyncio.Queue[tuple[str, dict]] = asyncio.Queue()
        
        async def produce_messages():
            try:
                while True:
                    if session_id in message_queues and message_queues[session_id]:
                        data = message_queues[session_id].popleft()
                        
                        await queue.put(
                            (
                                "message",
                                {
                                    "type": data["type"],
                                    "text": data["text"],
                                    "timestamp": datetime.now().isoformat(),
                                    "session_id": session_id,
                                }
                            )
                        )
                    else:
                        await asyncio.sleep(0.01)
            
            except asyncio.CancelledError:
                if session_id in message_queues:
                    del message_queues[session_id]
                
                await queue.put(
                    (
                        "end",
                        {
                            "status": "completed",
                            "timestamp": datetime.now().isoformat(),
                            "session_id": session_id,
                        }
                    )
                )
        
        async def produce_ping():
            try:
                while True:
                    await asyncio.sleep(5)
                    await queue.put(
                        (
                            "ping",
                            {
                                "status": "ping",
                                "timestamp": datetime.now().isoformat(),
                                "session_id": session_id,
                            }
                        )
                    )
            except asyncio.CancelledError:
                pass
        
        message_task = asyncio.create_task(produce_messages())
        ping_task = asyncio.create_task(produce_ping())
        
        try:
            while True:
                event_type, data = await queue.get()
                yield await sse_event(event_type, data)
                
                if event_type == "end":
                    break
        
        except Exception as e:
            yield await sse_event(
                "error",
                {
                    "code": 500,
                    "message": str(e),
                    "timestamp": datetime.now().isoformat(),
                    "session_id": session_id,
                }
            )
            yield await sse_event(
                "end",
                {
                    "status": "error_completed",
                    "timestamp": datetime.now().isoformat(),
                    "session_id": session_id,
                }
            )
        
        finally:
            ping_task.cancel()
            if not message_task.done():
                message_task.cancel()
            await asyncio.gather(ping_task, message_task, return_exceptions=True)
    
    headers = {
        "Cache-Control": "no-cache",
        "Content-Type": "text/event-stream",
        "Connection": "keep-alive",
        "X-Accel-Buffering": "no",
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Headers": "*",
        "Access-Control-Allow-Methods": "*",
    }
    
    return StreamingResponse(
        event_generator(),
        media_type="text/event-stream",
        headers=headers
    )